<% if false # the license inside this if block pertains to this file -%>
# Copyright 2017 Google Inc.
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
#     http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
<% end -%>
<%= lines(autogen_notice :go) -%>

package <%= package %>

<%= lines(compile(object.custom_code.constants)) if object.custom_code.constants %>

<%
  resource_name = product_ns + object.name + object.version.upcase
  resource_nestedobj_properties = nestedobject_properties(object)
  ai_name = resource_nestedobj_properties.nil? ? "nil" : "arrayIndex"
  united_async, gasync = is_united_async(object)
-%>

func resource<%= resource_name -%>() *schema.Resource {
    return &schema.Resource{
        Create: resource<%= resource_name -%>Create,
        Read: resource<%= resource_name -%>Read,
        <% if updatable?(object) -%>
        Update: resource<%= resource_name -%>Update,
        <% end -%>
        Delete: resource<%= resource_name -%>Delete,
        <% if import_resource?(object) -%>

        Importer: &schema.ResourceImporter{
            State: schema.ImportStatePassthrough,
        },
        <% end -%>
        <% at = async_timout(object) %>
        <% unless at.empty? -%>
        Timeouts: &schema.ResourceTimeout {
            <% unless at["create"].nil? -%>
            Create: schema.DefaultTimeout(<%= sprintf('%d',  at["create"] / 60) -%> * time.Minute),
            <% end -%>
            <% unless at["update"].nil? -%>
            Update: schema.DefaultTimeout(<%= sprintf('%d',  at["update"] / 60) -%> * time.Minute),
            <% end -%>
            <% unless at["delete"].nil? -%>
            Delete: schema.DefaultTimeout(<%= sprintf('%d',  at["delete"] / 60) -%> * time.Minute),
            <% end -%>
        },
        <% end -%>

        Schema: map[string]*schema.Schema{
<% order_properties(object.all_user_properties).each do |prop| -%>
    <%= lines(build_schema_property(prop, object)) -%>

<% end -%>
        },
    }
}

func resource<%= resource_name -%>UserInputParams(d *schema.ResourceData) map[string]interface{} {
    return map[string]interface{}{
        "terraform_resource_data": d,
<% object.not_output_properties.sort_by(&:out_name).each do |prop| -%>
        "<%= prop.out_name %>": d.Get("<%= prop.out_name %>"),
<% end -%>
    }
}

<% create_api = object.create_api -%>
func resource<%= resource_name -%>Create(d *schema.ResourceData, meta interface{}) error {
    config := meta.(*Config)
    client, err := config.sdkClient(<%= argu_for_sdkclient(create_api) %>)
    if err != nil {
        return fmt.Errorf("Error creating sdk client, err=%s", err)
    }

    opts := resource<%= resource_name -%>UserInputParams(d)
<% unless create_api.parameters.select { |i| i.name.downcase.eql?("region") }.empty? -%>
<%   if find_property(object, ["region"]).nil? -%>
    opts["region"] = GetRegion(d, config)
<%   end -%>
<% end -%>
<% unless resource_nestedobj_properties.nil? -%>

    arrayIndex := map[string]int{
<%   resource_nestedobj_properties.each do |i| -%>
        "<%= to_schema_index(i) %>": 0,
<%   end -%>
    }
<% end -%>

    params, err := build<%= resource_name -%>CreateParameters(opts, <%= ai_name -%>)
    if err != nil {
        return fmt.Errorf("Error building the request body of api(<%= create_api.name -%>), err=%s", err)
    }
    r, err := send<%= resource_name -%>CreateRequest(d, params, client)
    if err != nil {
        return fmt.Errorf("Error creating <%= resource_name -%>, err=%s", err)
    }
<% unless at["create"].nil? -%>

    timeout := d.Timeout(schema.TimeoutCreate)
<% end -%>
<% pre_api = create_api -%>
<% action = action_after_send_create_request(object) -%>
<% unless action.nil? -%>
<%   fn = sprintf("%s%s", resource_name, titlelize(action.name)) -%>

<%   unless action.parameters.nil? -%>
    params, err = build<%= fn -%>Parameters(opts, <%= ai_name -%>)
    if err != nil {
        return fmt.Errorf("Error building the request body of api(<%= action.name -%>), err=%s", err)
    }
<%   end -%>
<%   ncl = need_build_new_client(action, pre_api) -%>
<%   if ncl -%>
    client1, err = config.sdkClient(<%= argu_for_sdkclient(action) %>)
    if err != nil {
        return fmt.Errorf("Error creating sdk client, err=%s", err)
    }
<%   end -%>
<%   r = action.async.nil? ? "_, err =" : "ar, err :=" -%>
    <%= r %> send<%= fn %>Request(d, <%= action.parameters.nil? ? "nil" : "params" %><%= action.path_parameter.nil? ? "" : ", r" %>, <%= ncl ? "client1" : "client" %>)
    if err != nil {
        return err
    }
<%   unless action.async.nil? -%>
<%     async_op = action.async.operation -%>
<%     ncl1 = need_build_new_client(action, async_op) -%>
<%     if ncl1 -%>
    client1, err = config.sdkClient(<%= argu_for_sdkclient(async_op) %>)
    if err != nil {
        return fmt.Errorf("Error creating async sdk client, err=%s", err)
    }
<%     end -%>
    _, err = asyncWait<%= fn %>(d, config, ar, <%= ncl1 || ncl ? "client1" : "client" %>, timeout)
    if err != nil {
        return err
    }
<%   end -%>
<% end -%>

<% if create_api.async.nil? -%>
    id, err := navigateValue(r, []string{<%= index2navigate(create_api.resource_id_path) %>}, nil)
    if err != nil {
        return fmt.Errorf("Error constructing id, err=%s", err)
    }
    d.SetId(convertToStr(id))
<% else -%>
<%   async_op = create_api.async.operation -%>
<%   ncl = need_build_new_client(pre_api, async_op) -%>
<%   if ncl -%>
    client1, err = config.sdkClient(<%= argu_for_sdkclient(async_op) %>)
    if err != nil {
        return fmt.Errorf("Error creating async sdk client, err=%s", err)
    }
<%   end -%>
    obj, err := asyncWait<%= resource_name %>Create(d, config, r, <%= ncl ? "client1" : "client" %>, timeout)
    if err != nil {
        return err
    }
    id, err := navigateValue(obj, []string{<%= index2navigate(create_api.async.result.field) %>}, nil)
    if err != nil {
        return fmt.Errorf("Error constructing id, err=%s", err)
    }
    d.SetId(convertToStr(id))
<% end # unless object.async -%>
<% other_api(object, "c").each do | item | -%>
<%   fn = sprintf("%s%s", resource_name, titlelize(item.name)) -%>

<%   unless item.parameters.nil? -%>
    params, err = build<%= fn -%>Parameters(opts, <%= ai_name -%>)
    if err != nil {
        return fmt.Errorf("Error building the request body of api(<%= item.name -%>), err=%s", err)
    }
    if e, _ := isEmptyValue(reflect.ValueOf(params)); !e {
<%   end -%>
<%   ncl = need_build_new_client(item, pre_api) -%>
<%   if ncl -%>
    client1, err = config.sdkClient(<%= argu_for_sdkclient(item) %>)
    if err != nil {
        return fmt.Errorf("Error creating sdk client, err=%s", err)
    }
<%   end -%>
<%   r = item.async.nil? ? "_, err =" : "r, err =" -%>
    <%= r %> send<%= fn %>Request(d, <%= item.parameters.nil? ? "nil" : "params" %>, <%= ncl ? "client1" : "client" %>)
    if err != nil {
        return err
    }
<%   unless item.async.nil? -%>
<%     async_op = item.async.operation -%>
<%     ncl1 = need_build_new_client(item, async_op) -%>
<%     if ncl1 -%>
    client1, err = config.sdkClient(<%= argu_for_sdkclient(async_op) %>)
    if err != nil {
        return fmt.Errorf("Error creating async sdk client, err=%s", err)
    }
<%     end -%>
    _, err = asyncWait<%= fn %>(d, config, r, <%= ncl1 || ncl ? "client1" : "client" %>, timeout)
    if err != nil {
        return err
    }
<%   end -%>
<%   unless item.parameters.nil? -%>
    }
<%   end -%>
<% end -%>

    return resource<%= resource_name -%>Read(d, meta)
}

<% list_api = object.list_api
   read_api = object.read_api
-%>
<% if !read_api.nil? -%>
func resource<%= resource_name -%>Read(d *schema.ResourceData, meta interface{}) error {
    config := meta.(*Config)
    client, err := config.sdkClient(<%= argu_for_sdkclient(read_api) %>)
    if err != nil {
        return fmt.Errorf("Error creating sdk client, err=%s", err)
    }

    res := make(map[string]interface{})
<% read_apis = [read_api, other_api(object, "r")].flatten.compact -%>
<% multi_api = read_apis.length > 1 -%>
<% if multi_api -%>
    var v interface{}
<% end -%>
<% pre_api = read_api -%>
<% read_apis.each do | item | -%>

<%   ncl = need_build_new_client(pre_api, item) -%>
<%   if ncl -%>
    client1, err = config.sdkClient(<%= argu_for_sdkclient(item) %>)
    if err != nil {
        return nil, fmt.Errorf("Error creating sdk client, err=%s", err)
    }
<%   end -%>
    v, err <%= multi_api ? "=" : ":=" %> send<%= resource_name %><%= titlelize(item.name) %>Request(d, <%= ncl ? "client1" : "client" %>)
    if err != nil {
        return err
    }
    res["<%= item.name %>"] = fill<%= resource_name %><%= titlelize(item.name) %>RespBody(v)
<% end -%>

    states, err := flatten<%= resource_name -%>Options(res)
    if err != nil {
        return err
    }
<% unless properties_to_adjust(object).empty? -%>

    opts := resource<%= resource_name -%>UserInputParams(d)
    err = adjust<%= resource_name -%>Options(opts, states)
    if err != nil {
        return err
    }
<% end -%>

    return set<%= resource_name -%>States(d, states)
}
<% elsif !list_api.nil? -%>
func resource<%= resource_name -%>Read(d *schema.ResourceData, meta interface{}) error {
    config := meta.(*Config)
    client, err := config.sdkClient(<%= argu_for_sdkclient(list_api) %>)
    if err != nil {
        return fmt.Errorf("Error creating sdk client, err=%s", err)
    }

    res := make(map[string]interface{})

    v, err := fetch<%= resource_name %>By<%= titlelize(list_api.name) %>(d, client)
    if err != nil {
        return err
    }
    res["<%= list_api.name %>"] = fill<%= resource_name %><%= titlelize(list_api.name) %>RespBody(v)
<% pre_api = list_api -%>
<% read_apis = other_api(object, "r") -%>
<% read_apis.each do | item | -%>

<%   ncl = need_build_new_client(pre_api, item) -%>
<%   if ncl -%>
    client1, err = config.sdkClient(<%= argu_for_sdkclient(item) %>)
    if err != nil {
        return nil, fmt.Errorf("Error creating sdk client, err=%s", err)
    }
<%   end -%>
    v, err = send<%= resource_name %><%= titlelize(item.name) %>Request(d, <%= ncl ? "client1" : "client" %>)
    if err != nil {
        return err
    }
    res["<%= item.name %>"] = fill<%= resource_name %><%= titlelize(item.name) %>RespBody(v)
<% end -%>

    states, err := flatten<%= resource_name -%>Options(res)
    if err != nil {
        return err
    }
<% unless properties_to_adjust(object).empty? -%>

    opts := resource<%= resource_name -%>UserInputParams(d)
    err = adjust<%= resource_name -%>Options(opts, states)
    if err != nil {
        return err
    }
<% end -%>

    return set<%= resource_name -%>States(d, states)
}
<% end -%>
<% if updatable?(object) -%>
<%   update_api = object.update_api -%>
<%   update_apis = [update_api, other_api(object, "u")].flatten.compact -%>
<%   multi_update = update_apis.length > 1 -%>
<%   if multi_update -%>

func resource<%= resource_name -%>UserInputUpdateParams(d *schema.ResourceData) (oldState, newState map[string]interface{}) {
    oldState["terraform_resource_data"] = d
    newState["terraform_resource_data"] = d
<%     object.not_output_properties.sort_by(&:out_name).each do |prop| -%>
<%       next unless prop.crud.include?("u") -%>

    oldState["<%= prop.out_name %>"], newState["<%= prop.out_name %>"] = d.GetChange("<%= prop.out_name %>")
<%     end -%>
}
<%   end -%>

func resource<%= resource_name -%>Update(d *schema.ResourceData, meta interface{}) error {
    config := meta.(*Config)
<%   if update_api%>
    client, err := config.sdkClient(<%= argu_for_sdkclient(update_api) %>)
    if err != nil {
        return fmt.Errorf("Error creating sdk client, err=%s", err)
    }
<%   end -%>

<%   if multi_update -%>
    oldState, newState := resource<%= resource_name -%>UserInputUpdateParams(d)
<%   else -%>
    opts := resource<%= resource_name -%>UserInputParams(d)
<%   end -%>
<%   unless resource_nestedobj_properties.nil? -%>

    arrayIndex := map[string]int{
<%     resource_nestedobj_properties.each do |i| -%>
        "<%= to_schema_index(i) %>": 0,
<%     end -%>
    }
<%   end -%>
<%   unless at["update"].nil? -%>
    timeout := d.Timeout(schema.TimeoutUpdate)
<%   end -%>
<%   if multi_update -%>
    var r, params, params1 interface{}
<%   end -%>
<%   assign = multi_update ? "=" : ":=" -%>
<%   pre_api = update_api -%>
<%   unless update_api.nil? -%>

    params, err <%= assign %> build<%= resource_name -%>UpdateParameters(<%= multi_update ? "newState" : "opts" %>, <%= ai_name -%>)
    if err != nil {
        return fmt.Errorf("Error building the request body of api(<%= update_api.name -%>), err=%s", err)
    }
<%     if multi_update -%>
    params1, err <%= assign %> build<%= resource_name -%>UpdateParameters(oldState, <%= ai_name -%>)
    if err != nil {
        return fmt.Errorf("Error building the request body of api(<%= update_api.name -%>), err=%s", err)
    }
    if e, _ := isEmptyValue(reflect.ValueOf(params)); !(e || reflect.DeepEqual(params, params1)) {
<%     else -%>
    if e, _ := isEmptyValue(reflect.ValueOf(params)); !e {
<%     end -%>
<%     r = update_api.async.nil? ? "_, err =" : "r, err " + assign -%>
        <%= r %> send<%= resource_name -%>UpdateRequest(d, params, client)
        if err != nil {
            return fmt.Errorf("Error updating (<%= resource_name -%>: %v), err=%s", d.Id(), err)
        }
<%     unless update_api.async.nil? -%>
<%       async_op = update_api.async.operation -%>
<%       ncl = need_build_new_client(pre_api, async_op) -%>
<%       if ncl -%>
        client1, err = config.sdkClient(<%= argu_for_sdkclient(async_op) %>)
        if err != nil {
            return nil, fmt.Errorf("Error creating async sdk client, err=%s", err)
        }
<%       end -%>
        _, err = asyncWait<%= resource_name %>Update(d, config, r, <%= ncl ? "client1" : "client" %>, timeout)
        if err != nil {
            return err
        }
<%     end -%>
    }
<%   end # update_api.nil -%>
<%   other_updates = other_api(object, "u") -%>
<%   if !other_updates.empty? && update_api.nil? -%>
<%     pre_api = other_updates[0] -%>
    client := config.sdkClient(<%= argu_for_sdkclient(pre_api) %>)
<%   end -%>
<%   other_updates.each do | item | -%>
<%     fn = sprintf("%s%s", resource_name, titlelize(item.name)) -%>

<%     unless item.parameters.nil? -%>
    params, err <%= assign %> build<%= fn -%>Parameters(<%= multi_update ? "newState" : "opts" %>, <%= ai_name -%>)
    if err != nil {
        return fmt.Errorf("Error building the request body of api(<%= item.name -%>), err=%s", err)
    }
<%       if multi_update -%>
    params1, err <%= assign %> build<%= fn -%>Parameters(oldState, <%= ai_name -%>)
    if err != nil {
        return fmt.Errorf("Error building the request body of api(<%= item.name -%>), err=%s", err)
    }
    if e, _ := isEmptyValue(reflect.ValueOf(params)); !(e || reflect.DeepEqual(params, params1)) {
<%       else -%>
    if e, _ := isEmptyValue(reflect.ValueOf(params)); !e {
<%       end -%>
<%     end -%>
<%     ncl = need_build_new_client(pre_api, item) -%>
<%     if ncl -%>
    client1, err = config.sdkClient(<%= argu_for_sdkclient(item) %>)
    if err != nil {
        return nil, fmt.Errorf("Error creating async sdk client, err=%s", err)
    }
<%     end -%>
<%     r = item.async.nil? ? "_, err =" : "r, err " + assign -%>
    <%= r %> send<%= fn %>Request(d, <%= item.parameters.nil? ? "nil" : "params" %>, <%= ncl ? "client1" : "client" %>)
    if err != nil {
        return err
    }
<%     unless item.async.nil? -%>
<%       async_op = item.async.operation -%>
<%       ncl1 = need_build_new_client(item, async_op) -%>
<%       if ncl1 -%>
    client1, err = config.sdkClient(<%= argu_for_sdkclient(async_op) %>)
    if err != nil {
        return nil, fmt.Errorf("Error creating async sdk client, err=%s", err)
    }
<%       end -%>
    _, err = asyncWait<%= fn %>(d, config, r, <%= ncl1 || ncl ? "client1" : "client" %>, timeout)
    if err != nil {
        return err
    }
<%     end -%>
<%     unless item.parameters.nil? -%>
    }
<%     end -%>
<%   end -%>

    return resource<%= resource_name -%>Read(d, meta)
}
<% end -%>

<% delete_api = object.delete_api -%>
func resource<%= resource_name -%>Delete(d *schema.ResourceData, meta interface{}) error {
    config := meta.(*Config)
    client, err := config.sdkClient(<%= argu_for_sdkclient(delete_api) %>)
    if err != nil {
        return fmt.Errorf("Error creating sdk client, err=%s", err)
    }

    url, err := replaceVars(d, "<%= delete_api.path -%>", nil)
    if err != nil {
        return err
    }
    url = client.ServiceURL(url)

<% unless delete_api.parameters.nil? -%>
    opts := resource<%= resource_name -%>UserInputParams(d)
<%   unless resource_nestedobj_properties.nil? -%>
    arrayIndex := map[string]int{
<%     resource_nestedobj_properties.each do |i| -%>
        "<%= to_schema_index(i) %>": 0,
<%     end -%>
    }

<%   end -%>
    params, err := build<%= resource_name -%>DeleteParameters(opts, <%= ai_name %>)
    if err != nil {
        return fmt.Errorf("Error building the request body of api(delete), err=%s", err)
    }

<% end -%>
    log.Printf("[DEBUG] Deleting <%= object.name -%> %q", d.Id())
    r := golangsdk.Result{}
    _, r.Err = client.Delete(url, &golangsdk.RequestOpts{
        OkCodes: successHTTPCodes,
        JSONBody: <%= delete_api.parameters.nil? ? "nil" : "params" %>,
        JSONResponse: <%= delete_api.has_response ? "&r.Body" : "nil" %>,
        <% if delete_api.header_params.nil? -%>
        MoreHeaders:  map[string]string{"Content-Type": "application/json"},
        <% else -%>
        MoreHeaders: map[string]string{
            "Content-Type": "application/json",
          <% delete_api.header_params.each do |k, v| -%>
            <%= sprintf("\"%s\": \"%s\",", k, v)%>
          <% end -%>
        },
        <% end -%>
    })
    if r.Err != nil {
        return fmt.Errorf("Error deleting <%= object.name -%> %q, err=%s", d.Id(), r.Err)
    }
<% if delete_api.async.nil? -%>
<%   if create_api.async.nil? -%>

    return nil
<%   else # if create api is async, then it is best to make sure the resource is delete successfully -%>
<%     if !read_api.nil? -%>
<%       unless delete_api.path.eql?(read_api.path) -%>

    url, err = replaceVars(d, "<%= read_api.path -%>", nil)
    if err != nil {
        return err
    }
    url = client.ServiceURL(url)
<%       end -%>
<%       ncl = need_build_new_client(delete_api, read_api) -%>
<%       if ncl -%>

    client, err = config.sdkClient(<%= argu_for_sdkclient(read_api) %>)
    if err != nil {
        return nil, fmt.Errorf("Error creating sdk client, err=%s", err)
    }
<%       end -%>

    _, err = waitToFinish(
        []string{"Done"}, []string{"Pending"},
        d.Timeout(schema.TimeoutCreate),
        <%= sprintf('%d', create_api.async.operation.wait_ms / 1000) %> * time.Second,
        func() (interface{}, string, error) {
            _, err := client.Get(url, nil, &golangsdk.RequestOpts{
            <% if read_api.header_params.nil? -%>
                MoreHeaders: map[string]string{"Content-Type": "application/json"}})
            <% else -%>
                MoreHeaders: map[string]string{
                    "Content-Type": "application/json",
              <% read_api.header_params.each do |k, v| -%>
                    <%= sprintf("\"%s\": \"%s\",", k, v)%>
              <% end -%>
            }})
            <% end -%>
            if err != nil {
                if _, ok := err.(golangsdk.ErrDefault404); ok{
                    return true, "Done", nil
                }
                return nil, "", nil
            }
            return true, "Pending", nil
        },
    )
    return err
<%     elsif !list_api.nil? -%>
<%       ncl = need_build_new_client(delete_api, list_api) -%>
<%       if ncl -%>

    client, err = config.sdkClient(<%= argu_for_sdkclient(list_api) %>)
    if err != nil {
        return nil, fmt.Errorf("Error creating sdk client, err=%s", err)
    }
<%       end -%>

    _, err = waitToFinish(
        []string{"Done"}, []string{"Pending"},
        d.Timeout(schema.TimeoutCreate),
        <%= sprintf('%d', create_api.async.operation.wait_ms / 1000) %> * time.Second,
        func() (interface{}, string, error) {
            _, err := fetch<%= resource_name %>By<%= titlelize(list_api.name) %>(d, client)
            if err != nil {
                if strings.Index(err.Error(), "Error finding the resource by list api") != -1 {
                     return true, "Done", nil
                }
                return nil, "", nil
            }
            return true, "Pending", nil
        },
    )
    return err
<%     end -%>
<%   end -%>
<% else -%>
<%   async_op = delete_api.async.operation -%>
<%   ncl = need_build_new_client(delete_api, async_op) -%>
<%   if ncl -%>

    client, err = config.sdkClient(<%= argu_for_sdkclient(async_op) %>)
    if err != nil {
        return nil, fmt.Errorf("Error creating async sdk client, err=%s", err)
    }
<%       end -%>

    _, err = asyncWait<%= resource_name %><%= titlelize(delete_api.name) %>(d, config, r.Body, client, d.Timeout(schema.TimeoutDelete))
    return err
<% end -%>
}
<% req_apis = req_apis(object) -%>
<% not_read_api(object).each do | k, item | -%>
<%   unless item.parameters.nil? -%>

<%= lines(build_request_body_method(object, resource_name, item), 1) -%>
<%   end -%>
<%   next unless req_apis.include?(k) -%>
<%   unless object.is_delete_api(item) -%>

<%= lines(build_send_request_method(resource_name, item), 1) -%>
<%   end -%>
<%   unless item.async.nil? || united_async -%>

<%= lines(build_resource_async_op(item, resource_name, nil), 1) %>
<%   end -%>
<% end -%>
<% if united_async -%>

<%= lines(build_resource_async_op(nil, resource_name, gasync)) -%>
<% end -%>
<% read_apis.each do | item | -%>

<%= lines(build_read_method(resource_name, item), 1) -%>

<%= lines(build_fill_resp_body_method(item, resource_name)) -%>
<% end -%>
<% if read_api.nil? and !list_api.nil? -%>

<%= lines(build_list_method(object, resource_name, list_api), 1) -%>

<%= lines(build_list_method_filter(resource_name, list_api), 1) -%>

<%= lines(build_read_method(resource_name, list_api, true), 1) -%>

<%= lines(build_fill_resp_body_method(list_api, resource_name)) -%>
<% end -%>

<%= lines(build_convert_opts_method(object, resource_name), 1) -%>
<%= lines(build_adjust_opts_method(object, resource_name), 1) -%>

<%= lines(build_set_states_method(resource_name), 1) -%>
